Allow install of static slang library#11458
Conversation
The install(EXPORT SlangTargets) step and the UNIX pkgconfig install were skipped whenever SLANG_LIB_TYPE was STATIC. The guard was added in shader-slang#6158 to work around the export errors in shader-slang#5821: slang's internal link dependencies (core, prelude, compiler-core, slang-capability-*, slang-lookup-tables, SPIRV-Headers, ...) leaked onto its public link interface and weren't in any export set, so install(EXPORT ...) failed. That guard is now obsolete. slang_add_target wraps private link deps in $<BUILD_LOCAL_INTERFACE:...> / $<BUILD_INTERFACE:...>, so those targets no longer appear in the install/export interface and a static install exports cleanly. The guard also masked a second bug: configure_package_config_file runs unconditionally and the generated slangConfig.cmake unconditionally include()s slangTargets.cmake, so a static install used to ship a config that pointed at a Targets file that was never installed, making find_package(slang) fail with a confusing "file not found". Removing the guard fixes both: a static install now exports SlangTargets and find_package(slang) resolves the slang::slang target. Also add CI coverage: the CMake Options workflow already builds the SLANG_LIB_TYPE=STATIC entry, but only configured and built it and never ran cmake --install, so this regression would not have been caught. Add an install_test matrix flag and a 'cmake --install' step (in both the host and container build workflows) that runs for entries opting in via that flag. Fixes shader-slang#11359
📝 WalkthroughWalkthroughThis PR enables installation and CMake export of static library builds by removing a build-type condition that previously blocked ChangesStatic Library Export and Installation
Suggested reviewers
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: dba2233e-0bec-4ceb-ac59-8151b2518d11
📒 Files selected for processing (4)
.github/cmake-options-matrix.json.github/workflows/cmake-options-build-container.yml.github/workflows/cmake-options-build.ymlCMakeLists.txt
| # Exercise `cmake --install` for entries that opt in via install_test. | ||
| # The static-lib build (SLANG_LIB_TYPE=STATIC) used to skip the | ||
| # install(EXPORT ...) step entirely, so a broken export would not have | ||
| # been caught by a plain configure+build. See issue #11359. | ||
| - name: Install Slang (${{ matrix.option }}) | ||
| if: matrix.install_test == 'true' && matrix.windows_only != 'true' | ||
| run: cmake --install build --config "$cmake_config" --prefix install |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial | 🏗️ Heavy lift
Consider validating find_package(slang) after install, not just that cmake --install succeeds.
Issue #11359 manifested as find_package(slang) failing because slangTargets.cmake wasn't installed — yet the install command itself still succeeded with the old guard in place. The "not in any export set" failure is caught at configure/generate time now, but this step alone would not catch a future regression where the install completes but the exported package config is inconsistent. A minimal consumer find_package(slang CONFIG PATHS install ... NO_DEFAULT_PATH) check (resolving slang::slang) would directly guard the originally-reported breakage.
There was a problem hiding this comment.
Verdict: 🟡 Has issues — 2 gap(s)
Removes an obsolete if(NOT ${SLANG_LIB_TYPE} STREQUAL "STATIC") guard around install(EXPORT SlangTargets ...) and the UNIX pkgconfig install in CMakeLists.txt, fixing the static-install / find_package(slang) failure tracked in #11359, and adds an install_test matrix flag with a cmake --install step. Two gaps: the pkgconfig file is now installed for STATIC builds even though its template explicitly does not support static linking and lacks Libs.private; and the new cmake --install step doesn't exercise the find_package(slang) consumer path that originally broke.
Changes Overview
CMake export gating (CMakeLists.txt)
- What changed: removes the
if(NOT ${SLANG_LIB_TYPE} STREQUAL "STATIC")wrapper around bothinstall(EXPORT SlangTargets ...)and the UNIXslang-compiler.pcinstall. Adds a comment block documenting why the guard (originally added in #6158) is now obsolete:slang_add_targetwraps private link deps in$<BUILD_LOCAL_INTERFACE:...>/$<BUILD_INTERFACE:...>, so internal targets no longer leak onto the public export interface. This is verifiable incmake/SlangTarget.cmake(around lines 434-443) andcmake/SlangConfig.cmake.in.
Install regression coverage (.github/cmake-options-matrix.json, .github/workflows/cmake-options-build.yml, .github/workflows/cmake-options-build-container.yml)
- What changed: introduces a new
install_testmatrix flag, set on theSLANG_LIB_TYPE=STATICentry, and an "Install Slang" step in both the host and containercmake-optionsworkflows that runscmake --install build --config "$cmake_config" --prefix installfor entries opting in.
Findings (2 total)
| Severity | Location | Finding |
|---|---|---|
| 🟡 Gap | CMakeLists.txt:694 |
pkgconfig file is now installed for STATIC builds, but the .pc.in template doesn't populate Libs.private and explicitly says static linking is unsupported |
| 🟡 Gap | .github/workflows/cmake-options-build.yml:187 |
New cmake --install step doesn't exercise the find_package(slang) consumer path that originally broke in #11359 |
| endif() | ||
| # TODO: When build system is changed to respect CMAKE_INSTALL_LIBDIR, | ||
| # update this destination. | ||
| install( |
There was a problem hiding this comment.
🟡 Gap: pkgconfig file installed for STATIC builds, but .pc template explicitly does not support static linking
Removing the STATIC guard makes install(FILES "${PROJECT_BINARY_DIR}/slang-compiler.pc" DESTINATION "lib/pkgconfig") fire for UNIX static builds too. extras/pkgconfig/slang-compiler.pc.in is not equipped for that case:
Libs: -L${libdir} -lslang-compiler
Cflags: -I${includedir}
# Note: pkg-config --static is not currently supported,
# so Libs.private is not populated.
Libs: names only -lslang-compiler and Libs.private is empty. After a STATIC install, pkg-config --libs slang-compiler returns an incomplete link line that omits every transitive internal archive (core, compiler-core, slang-capability-*, slang-lookup-tables, plus bundled vendored libs like miniz/lz4 — see docs/building.md listing the static dependency chain). pkg-config users following the manifest will hit unresolved-symbol errors at link time.
Example: a downstream UNIX project does pkg-config --libs slang-compiler after cmake --install of a SLANG_LIB_TYPE=STATIC Slang. They get -L<prefix>/lib -lslang-compiler and ld reports unresolved references into core::* and compiler-core::*. Before this PR, no .pc was installed so the project would fall back to find_package(slang) (which is the well-supported path with this PR).
Suggested fix: either keep the pkgconfig install gated on shared (the simplest patch and consistent with the .pc.in comment), or populate Libs.private with the full static dependency chain when SLANG_LIB_TYPE is STATIC and document that pkg-config --static --libs slang-compiler is required.
if(UNIX AND NOT ${SLANG_LIB_TYPE} STREQUAL "STATIC")
configure_file(...)
install(FILES "${PROJECT_BINARY_DIR}/slang-compiler.pc" DESTINATION "lib/pkgconfig")
endif()| # been caught by a plain configure+build. See issue #11359. | ||
| - name: Install Slang (${{ matrix.option }}) | ||
| if: matrix.install_test == 'true' && (matrix.linux_only != 'true' || inputs.os == 'linux') && (matrix.windows_only != 'true' || inputs.os == 'windows') && matrix.container_only != 'true' && (matrix.skip_linux_aarch64 != 'true' || inputs.os != 'linux' || inputs.platform != 'aarch64') | ||
| run: cmake --install build --config "$cmake_config" --prefix install |
There was a problem hiding this comment.
🟡 Gap: cmake --install doesn't exercise the consumer-side regression of #11359
The reported failure mode in #11359 is find_package(slang) blowing up on a static install because slangConfig.cmake always include()s a slangTargets.cmake that wasn't installed. The new step only runs cmake --install build --config "$cmake_config" --prefix install. That covers the case where install(EXPORT SlangTargets ...) itself errors at install time, but it doesn't exercise the actual user path that broke.
In particular, if a future change re-introduces a guard around just the install(EXPORT ...) call (the exact shape of the original bug), cmake --install still succeeds — it just silently doesn't ship slangTargets.cmake. The regression resurfaces only when a downstream calls find_package(slang), which CI never does.
Suggested fix: chain a tiny find_package smoke test after the install step. The slang_DIR path differs by OS because SLANG_CMAKE_CONFIG_DIR is cmake on Windows and ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME} elsewhere (CMakeLists.txt around line 652).
- name: Smoke-test find_package(slang) against install prefix
if: matrix.install_test == 'true' && (matrix.linux_only != 'true' || inputs.os == 'linux') && (matrix.windows_only != 'true' || inputs.os == 'windows') && matrix.container_only != 'true' && (matrix.skip_linux_aarch64 != 'true' || inputs.os != 'linux' || inputs.platform != 'aarch64')
shell: bash
run: |
mkdir -p find_pkg_test && cd find_pkg_test
cat > CMakeLists.txt <<'EOF'
cmake_minimum_required(VERSION 3.22)
project(find_slang_smoke LANGUAGES CXX)
find_package(slang CONFIG REQUIRED)
if(NOT TARGET slang::slang)
message(FATAL_ERROR "slang::slang target missing after find_package")
endif()
EOF
cmake -S . -B build -Dslang_ROOT="$GITHUB_WORKSPACE/install"Same change applies to .github/workflows/cmake-options-build-container.yml.
Summary
A static-library install of Slang was blocked by an obsolete guard in
CMakeLists.txt. Theinstall(EXPORT SlangTargets)step and the UNIX pkgconfig install were skipped wheneverSLANG_LIB_TYPE == STATIC.The guard was added in #6158 to work around the export errors in #5821: slang's internal link dependencies (
core,prelude,compiler-core,slang-capability-*,slang-lookup-tables,SPIRV-Headers, ...) leaked onto its public link interface and weren't in any export set, soinstall(EXPORT ...)failed.That guard is now obsolete.
slang_add_targetwraps private link deps in$<BUILD_LOCAL_INTERFACE:...>/$<BUILD_INTERFACE:...>(cmake/SlangTarget.cmake), so those targets no longer appear in the install/export interface and a static install exports cleanly.The guard also masked a second bug:
configure_package_config_fileruns unconditionally and the generatedslangConfig.cmakeunconditionallyinclude()sslangTargets.cmake(cmake/SlangConfig.cmake.in). With the guard, a static install shipped a config that pointed at a Targets file that was never installed, sofind_package(slang)failed with a confusing "file not found." Removing the guard fixes this too.CI coverage
The CMake Options workflow already builds the
SLANG_LIB_TYPE=STATICentry, but only configured and built it and never rancmake --install— so this regression would not have been caught. This PR adds aninstall_testmatrix flag and acmake --installstep (in both the host and container build workflows) that runs for entries opting in via that flag.Verification
Locally on macOS (CMake 4.3.3,
SLANG_LIB_TYPE=STATIC):slangtarget'sINTERFACE_LINK_LIBRARIESis empty ($<LINK_ONLY:>) — no internal targets leak.cmake --installsucceeds and shipsslangTargets.cmake,slang-compiler.pc,slangConfig.cmake, andslangConfigVersion.cmake.find_package(slang CONFIG)against the install resolves theslang::slangtarget.The original reporter independently confirmed guard-less static installs succeed on both MSVC and gcc.
Fixes #11359